#include "tools.h"
#include "boost/serialization/serialization.hpp"
#include <boost/serialization/base_object.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include "boost/algorithm/string.hpp"
#include <boost/format.hpp>
#include <boost/filesystem/path.hpp>
#include "boost/date_time/posix_time/posix_time.hpp"
#include "glog/logging.h"
#include "backward.hpp"
#include <fstream>
#include <string>
#include "hemorrhage_extract.h"
#include <list>


using google::INFO;
using google::WARNING;
using google::FATAL;
using google::ERROR;
using boost::filesystem::path;
using boost::serialization::serialize;
//using caffe::Caffe;
using boost::format;
using std::string;
using std::vector;
using std::ifstream;
using std::ofstream;

DEFINE_string(basedir,
              "/home/d/data/base/",
              "directory that contains image files");
DEFINE_string(annotation,
              "Annotations.csv",
              "the minority samples classes");

DEFINE_string(result,
              "result.csv",
              "the minority samples classes");


class CSVFile {
public:
    class CSVelem {
    private:
        string raw;
    public:
        CSVelem(string _raw) {
            this->raw = _raw;
        }

        string getString() {
            return raw;
        }

        int getInt() {
            return stoi(raw);
        }

        double getDouble() {
            return stof(raw);
        }
    };

private:
    vector<vector<CSVelem> > lines;
    std::vector<CSVelem> title;

    std::vector<CSVelem> parseLine(string l) {
        assert(l.length());
        vector<string> elems;
        vector<CSVelem> tmpem;
        boost::split(elems, l, boost::is_any_of(","));
        for (auto it:elems) {
            tmpem.push_back(CSVelem(it));
        }
        return tmpem;
    }

public:
    CSVFile(string filename) {
        ifstream fin(filename);
        string l;
        getline(fin, l);
        title = parseLine(l);
        while (!fin.eof()) {
            getline(fin, l);
            if (l.length() == 0) break;
            lines.push_back(parseLine(l));
        }
    }

    vector<CSVelem> &operator[](const int nIndex) {
        return lines[nIndex];
    }

    vector<vector<CSVelem> > &operator()() {
        return lines;
    }

};

int calArea(CommonImage &cimg) {
    Mat img = cimg.getByte().getOriginal();
    return (int) sum(img / 255).val[0];
}


int main(int argc, char **argv) {
    srand((unsigned int) time(NULL));
    google::SetCommandLineOption("alsologtostderr", "true");
    google::SetCommandLineOption("colorlogtostderr", "true");
    google::InitGoogleLogging(argv[0]);
    google::SetUsageMessage(
            "Convert the original image set to lmdb database\n"
    );
    google::ParseCommandLineFlags(&argc, &argv, true);
    backward::SignalHandling sh;
    if (!sh.loaded()) {
        LOG(ERROR) << "BACKWARD NOT LOADED";
    }
    path baseDir = path(FLAGS_basedir);
    path annotation_file = baseDir / path(FLAGS_annotation);
    path out_file = baseDir / path(FLAGS_result);
//    assert(false);
    assert(exists(baseDir));
    assert(exists(annotation_file));

    // start of code
    ofstream fout("result.csv");
    fout << "filename,id,ma_count,ha_area,exclude_area,vessel_area";
    CSVFile csvFile(annotation_file.string());
#pragma omp parallel for shared(baseDir,csvFile)
    for (int index = 0; index < csvFile().size(); index++) {
        auto line = csvFile()[index];
        // if(index < 18)
        //     continue;
        string imgpath = (baseDir / path(line[0].getString())).string();
        LOG(INFO) << "Handling Image:" << imgpath << " " << line[1].getInt();
        Mat image = cv::imread(imgpath);
        // cv::resize(image, image,
        //    cv::Size(Parameters::IMAGE_COLS,
        //             image.rows * Parameters::IMAGE_COLS / image.cols));
        DRImage drImage(image, index);
        drImage.write(index);
        // CommonImage vesselImg(vessel_seg(drImage.getOriginal()), "vesselImg");
        // vesselImg.write(index);
        // float areave = calArea(vesselImg);
        auto res = bleed_process(drImage.getOriginal());
        CommonImage bleedImg(res.bleed, "bleed");
        bleedImg.write(index);
        float areableed = calArea(bleedImg);
        CommonImage Hardleakage(res.exclude, "hard");
        Hardleakage.write(index);
        float arealeakage = calArea(Hardleakage);
        fout << line[0].getString() << ","
             << index << ","
             << "-" << ","
             << areableed << ","
             // << arealeakage << ","
             << areableed << "\n";
    }
}